using Cronos;
using Microsoft.Extensions.Logging;

namespace TaskScheduler.Core;

/// <summary>
/// 任务调度器实现
/// </summary>
public class TaskScheduler : ITaskScheduler, IDisposable
{
    private readonly ILogger<TaskScheduler> _logger;
    private readonly Dictionary<string, ITask> _tasks = new();
    private readonly Dictionary<string, Timer> _timers = new();
    private readonly object _lock = new();
    private bool _disposed;

    /// <summary>
    /// 构造函数，注入日志服务
    /// </summary>
    /// <param name="logger">日志服务</param>
    public TaskScheduler(ILogger<TaskScheduler> logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 添加任务到调度器
    /// </summary>
    /// <param name="task">要添加的任务</param>
    public void AddTask(ITask task)
    {
        if (task == null)
            throw new ArgumentNullException(nameof(task));

        lock (_lock)
        {
            if (_tasks.ContainsKey(task.TaskName))
            {
                _logger.LogWarning("任务 {TaskName} 已存在，将被替换", task.TaskName);
                RemoveTask(task.TaskName);
            }

            _tasks[task.TaskName] = task;
            _logger.LogInformation("添加任务: {TaskName} - {Description}", task.TaskName, task.Description);
        }
    }

    /// <summary>
    /// 从调度器移除指定名称的任务
    /// </summary>
    /// <param name="taskName">任务名称</param>
    public void RemoveTask(string taskName)
    {
        if (string.IsNullOrEmpty(taskName))
            throw new ArgumentException("任务名称不能为空", nameof(taskName));

        lock (_lock)
        {
            if (_timers.TryGetValue(taskName, out var timer))
            {
                timer?.Dispose();
                _timers.Remove(taskName);
            }

            _tasks.Remove(taskName);
            _logger.LogInformation("移除任务: {TaskName}", taskName);
        }
    }

    /// <summary>
    /// 获取所有已注册的任务列表
    /// </summary>
    /// <returns>所有任务的枚举集合</returns>
    public IEnumerable<ITask> GetAllTasks()
    {
        lock (_lock)
        {
            return _tasks.Values.ToList();
        }
    }

    /// <summary>
    /// 启动调度器，为所有启用的任务启动定时器
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>异步任务</returns>
    public async Task StartAsync(CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("启动任务调度器");

        lock (_lock)
        {
            foreach (var task in _tasks.Values)
            {
                if (!task.IsEnabled)
                {
                    _logger.LogInformation("任务 {TaskName} 已禁用，跳过", task.TaskName);
                    continue;
                }

                StartTaskTimer(task);
            }
        }

        await Task.CompletedTask;
    }

    /// <summary>
    /// 停止调度器，释放所有定时器资源
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>异步任务</returns>
    public async Task StopAsync(CancellationToken cancellationToken = default)
    {
        _logger.LogInformation("停止任务调度器");

        lock (_lock)
        {
            foreach (var timer in _timers.Values)
            {
                timer?.Dispose();
            }
            _timers.Clear();
        }

        await Task.CompletedTask;
    }

    /// <summary>
    /// 手动执行指定名称的任务
    /// </summary>
    /// <param name="taskName">任务名称</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>任务执行结果</returns>
    public async Task<TaskResult> ExecuteTaskAsync(string taskName, CancellationToken cancellationToken = default)
    {
        if (string.IsNullOrEmpty(taskName))
            throw new ArgumentException("任务名称不能为空", nameof(taskName));

        ITask? task;
        lock (_lock)
        {
            if (!_tasks.TryGetValue(taskName, out task))
            {
                throw new InvalidOperationException($"任务 {taskName} 不存在");
            }
        }

        return await ExecuteTaskInternalAsync(task, cancellationToken);
    }

    /// <summary>
    /// 为指定任务启动定时器，根据 Cron 表达式计算下次执行时间
    /// </summary>
    /// <param name="task">要启动定时器的任务</param>
    private void StartTaskTimer(ITask task)
    {
        try
        {
            //计算cron表达式
            var cronExpression = CronExpression.Parse(task.CronExpression);
            var nextOccurrence = cronExpression.GetNextOccurrence(DateTime.UtcNow, TimeZoneInfo.Local);
            
            if (nextOccurrence.HasValue)
            {
                //转为当前时区
                var localTime = nextOccurrence.Value.ToLocalTime();
                var delay = localTime - DateTime.Now;
                if (delay.TotalMilliseconds > 0)
                {
                    //设置定时任务
                    var timer = new Timer(async _ => await ExecuteTaskWithReschedule(task), null, delay, Timeout.InfiniteTimeSpan);
                    _timers[task.TaskName] = timer;
                    
                    _logger.LogInformation("任务 {TaskName} 将在 {NextRun} 执行", task.TaskName, localTime);
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "启动任务 {TaskName} 的定时器时发生错误", task.TaskName);
        }
    }

    /// <summary>
    /// 执行任务并在完成后自动重新安排下次执行
    /// </summary>
    /// <param name="task">要执行的任务</param>
    private async Task ExecuteTaskWithReschedule(ITask task)
    {
        try
        {
            await ExecuteTaskInternalAsync(task);

            // 重新调度下次执行
            if (task.IsEnabled)
            {
                StartTaskTimer(task);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "执行任务 {TaskName} 时发生错误", task.TaskName);
            
            // 即使出错也要重新调度
            if (task.IsEnabled)
            {
                StartTaskTimer(task);
            }
        }
    }

    /// <summary>
    /// 实际执行任务的内部方法，记录执行时间和日志
    /// </summary>
    /// <param name="task">要执行的任务</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>任务执行结果</returns>
    private async Task<TaskResult> ExecuteTaskInternalAsync(ITask task, CancellationToken cancellationToken = default)
    {
        var startTime = DateTime.UtcNow;
        var stopwatch = System.Diagnostics.Stopwatch.StartNew();

        _logger.LogInformation("开始执行任务: {TaskName}", task.TaskName);

        var result = new TaskResult
        {
            ExecuteTime = startTime
        };

        try
        {
            result = await task.ExecuteAsync(cancellationToken);
            result.ExecuteTime = startTime;
            result.ElapsedMilliseconds = stopwatch.ElapsedMilliseconds;

            if (result.IsSuccess)
            {
                _logger.LogInformation("任务 {TaskName} 执行成功，耗时: {ElapsedMs}ms", task.TaskName, result.ElapsedMilliseconds);
            }
            else
            {
                _logger.LogWarning("任务 {TaskName} 执行失败: {Message}", task.TaskName, result.Message);
            }
        }
        catch (Exception ex)
        {
            result.IsSuccess = false;
            result.Message = ex.Message;
            result.Exception = ex;
            result.ElapsedMilliseconds = stopwatch.ElapsedMilliseconds;

            _logger.LogError(ex, "任务 {TaskName} 执行时发生异常", task.TaskName);
        }
        finally
        {
            stopwatch.Stop();
        }

        return result;
    }

    /// <summary>
    /// 释放调度器资源，清理所有定时器和任务
    /// </summary>
    public void Dispose()
    {
        if (!_disposed)
        {
            lock (_lock)
            {
                foreach (var timer in _timers.Values)
                {
                    timer?.Dispose();
                }
                _timers.Clear();
                _tasks.Clear();
            }
            _disposed = true;
        }
    }
} 